// HomeServerClass.h
// Define the CHomeServer.
// Kimi.Pu

#ifndef _HOME_SERVER_CLASS_
#define _HOME_SERVER_CLASS_

#include <process.h>

#include "../LibHttpServer/HttpServer.h"
#include "../ParseServer/ParseServerImpl.h"
#include "ServerInterface.h"
#include "status.h"
#include "../../../Components/Common/Libcommon/log.h"
#include "ServerConfig.h"

class CThreadEvent
{
public:
	CThreadEvent(unsigned int e, void * param):m_EventID(e), m_Param(param)
	{
		m_Result = HS_FAILED;
		m_ResultEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	}
	unsigned int		m_EventID;
	void *				m_Param;
	eHSResult			m_Result;
	HANDLE				m_ResultEvent;
	
	eHSResult Wait()
	{
		WaitForSingleObject(m_ResultEvent, INFINITE);
		return m_Result;
	}

	void Complete()
	{
		SetEvent(m_ResultEvent);
	}
};

class CThreadEventQueue
{
public:
	CThreadEventQueue()
	{
		m_Semaphore = CreateSemaphore(NULL, 0, 0xffff, NULL);
		m_Mutex = CreateMutex(NULL, FALSE, NULL);
	}
	~CThreadEventQueue()
	{
		CloseHandle(m_Semaphore);
		CloseHandle(m_Mutex);
	}
	void Push(CThreadEvent *Event)
	{
		DWORD res = WaitForSingleObject(m_Mutex, INFINITE);
		if (res == WAIT_OBJECT_0)
		{
			m_EventQueue.push_back(Event);
			ReleaseMutex(m_Mutex);
			ReleaseSemaphore(m_Semaphore, 1, NULL);
		}
	}
	bool Pop(CThreadEvent ** Event, DWORD WaitTime)
	{
		DWORD Res = WaitForSingleObject(m_Semaphore, WaitTime);
		if (Res == WAIT_OBJECT_0)
		{
			DWORD res = WaitForSingleObject(m_Mutex, INFINITE);
			if (res == WAIT_OBJECT_0)
			{
				*Event = m_EventQueue.front();
				m_EventQueue.pop_front();
				ReleaseMutex(m_Mutex);
				return true;
			}
			return false;
		}
		else
			return false;
	}
protected:
	std::deque<CThreadEvent*>	m_EventQueue;
	HANDLE						m_Semaphore;
	HANDLE						m_Mutex;
};

// CHomeServer is main module for handling HTTP Requesting from client
// and server panel.
class CHomeServer : public IHomeServer
{
	// Main Thread
	static unsigned int __stdcall MainServerThread(void* p);
	HANDLE				m_hMainThread;
	CThreadEventQueue	m_MainThreadEventQueue;

	// Currently, in DEMO, to simplify the working, we use MainServerThread
	// to handle all the requesting, which may cause long time hang.

	
	// Announce IP Thread
	static unsigned int __stdcall AnnounceIPThread(void * p);
	HANDLE m_hAnnounceIPThread;

	// Server Status
	CServerStatus m_Status;

	// Server Config
	CServerConfig m_Config;

	// Log
	tLog* m_pLog;

	std::deque<std::string> m_LocalIPList;

	// HTTP Server
	// Currently, no HTTP server instance, we use LibHTTP, which
	// is a C language codes.

	// Stop all the working thread for IP detect and login.
	eHSResult StopWorkThread();

	// Internal event handler.
	eHSResult InternalLogin();
	eHSResult InternalLogout();
	eHSResult InternalDetectIP();
	bool IsBehindNAT();
	eHSResult OpenUPnPNAT();
	void GetLocalIPList();
public:
	void SetLog(tLog * pLog);
	// Interface
	eHSResult StartServer();
	eHSResult StopServer();
	eHSResult WaitForStop();
	const wchar_t * GetErrorCode(eHSResult code);
	eHSResult Login(const wchar_t * username, const wchar_t * passwd);
	eHSResult Logout();
	CServerStatus GetStatus();
	const wchar_t * GetShareFolder(int index);
	eHSResult AddShareFolder(const wchar_t * folder);
	eHSResult RemoveShareFolder(const wchar_t * folder);
	const wchar_t * GetConfigPath();

	BOOL HandleAnounceIP();

	CHomeServer();
	~CHomeServer();
};

#endif